%% @author chenkangmin
-module(cus_push).


-include("cus.hrl").
-include("cus_pb.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").


%% ====================================================================
%% API functions
%% ====================================================================
-export([
    start/4,
    start/5,
    push_message/3,
    push/3,
    get_badge/1,
    clear_badge/2
        ]).


-define(DEFAULT, <<230,130,168,230,156,137,228,184,128,230,157,161,230,150,176,230,182,136,230,129,175>>).
-define(PROCNAME, 'cus_ios_provider_').
        


push_message(Uid, Cid, Alert) ->
    UserInfo = get_push_user_info(Uid),
    do_push_message(UserInfo, Cid, Alert).


push([], _Alert, _Extra) ->
    skip;
push([Uid | T], Alert, Extra) ->
    UserInfo = get_push_user_info(Uid),
    do_push(UserInfo, Alert, Extra),
    push(T, Alert, Extra).


do_push_message(undefined, _Cid, _Alert) ->
    skip;
do_push_message(UserInfo, Cid, Alert) ->
    Platform = UserInfo#cus_push_user.platform,
    PushKey = UserInfo#cus_push_user.pushKey,
    case UserInfo#cus_push_user.muteNotofication of
        0 ->
            case ?member(Cid, UserInfo#cus_push_user.muteNotofications) of
                false ->
                    RealAlert = real_alert(Alert, UserInfo#cus_push_user.pushContent),
                    real_push(Platform, PushKey, RealAlert, []);
                _ ->
                    skip
            end;
        _ ->
            skip
    end.


do_push(undefined, _Alert, _Extra) ->
    skip;
do_push(UserInfo, Alert, Extra) ->
    Platform = UserInfo#cus_push_user.platform,
    PushKey = UserInfo#cus_push_user.pushKey,
    case UserInfo#cus_push_user.muteNotofication of
        0 ->
            RealAlert = real_alert(Alert, UserInfo#cus_push_user.pushContent),
            real_push(Platform, PushKey, RealAlert, Extra);
        _ ->
            skip
    end.

real_alert(Alert, 0) ->
    Alert;
real_alert(_Alert, _) ->
    ?DEFAULT.


real_push("", _PushKey, _Alert, _Extra) ->
    skip;
real_push("ios", PushKey, Alert, Extra) ->
    Size = cus_config:ios_size(),
    Index = erlang:phash(PushKey, Size),
    ProcName = get_proc_name(Index),
    Pid1 = case whereis(ProcName) of
               undefined ->
                   case cus_config:ios() of
                       [Host, Cert, Key, _Size] ->
                           start_ios_provider([Host, Cert, Key], ProcName);
                       [Host, Cert, Key, Pwd, _Size] ->
                           start_ios_provider([Host, Cert, Key, Pwd], ProcName)
                   end;
               Pid ->
                   Pid
           end,
    cus_ios_provider:push(Pid1, PushKey, "default", Alert, Extra);
real_push("android", PushKey, Alert, Extra) ->
    PushJid = cus_util:make_jid(<<"server_push">>),
    ToJid = cus_util:make_jid(?l2b(PushKey)),
    FoldFun = fun({_, undefined}, Acc) ->
                      Acc;
                  ({Key, Value}, Acc) when is_list(Value) ->
                      [{Key, list_to_binary(Value)} | Acc];
                  ({Key, Value}, Acc) ->
                      [{Key, Value} | Acc];
                  (_Other, Acc) ->
                      Acc
              end,
    ExtraStr = case lists:foldl(FoldFun, [], Extra) of
                   [] ->
                       "";
                   _ ->
                       Json = {obj, lists:foldl(FoldFun, [], Extra)},
                       rfc4627:encode(Json)
               end,
    PushContent = #pushcontent{alert = Alert, extra = ExtraStr},
    ejabberd_router:route(PushJid, ToJid, PushContent).


get_proc_name(Index) ->
    Name = atom_to_list(?PROCNAME) ++ integer_to_list(Index),
    list_to_atom(Name).


start(Host, CertFile, KeyFile, Size) ->
    [spawn(fun() ->
                   ProcName = get_proc_name(N),
                   start_ios_provider([Host, CertFile, KeyFile], ProcName)
           end) || N <- lists:seq(1, Size)],
    create_table(),
    ?INFO_MSG("cus ios provider start success", []).


start(Host, CertFile, KeyFile, Pwd, Size) ->
    [spawn(fun() ->
                   ProcName = get_proc_name(N),
                   start_ios_provider([Host, CertFile, KeyFile, Pwd], ProcName)
           end) || N <- lists:seq(1, Size)],
    create_table(),
    ?INFO_MSG("cus ios provider start success", []).


create_table() ->
    %%缓存push用户信息表
    cus_util:new_table(cus_push_user_tab, [{record_name, cus_push_user},
                                           {attributes, record_info(fields, cus_push_user)},
                                           {ram_copies, [node()]}], ram_copies),
    cus_util:new_table(cus_push_badge_tab, [{record_name, cus_push_badge},
                                            {attributes, record_info(fields, cus_push_badge)},
                                            {ram_copies, [node()]}], ram_copies).


start_ios_provider(Conf, ProcName) ->
    case cus_ios_provider:start(Conf) of
        {ok, Client} ->
            register(ProcName, Client),
            Client;
        {error, _} = Err ->
            Err
    end.


get_badge(Token) ->
    case mnesia:dirty_read(cus_push_badge_tab, Token) of
        [] ->
            BadgeInfo = #cus_push_badge{deviceToken = Token, badge = 1},
            mnesia:dirty_write(cus_push_badge_tab, BadgeInfo),
            1;
        [Info] ->
            Badge = Info#cus_push_badge.badge,
            Info1 = Info#cus_push_badge{badge = Badge + 1},
            mnesia:dirty_write(cus_push_badge_tab, Info1),
            Badge + 1
    end.


clear_badge(Token, 0) ->
    mnesia:dirty_delete(cus_push_badge_tab, Token);
clear_badge(Token, Count) ->
    case mnesia:dirty_read(cus_push_badge_tab, Token) of
        [] ->
            skip;
        [Info] ->
            Info1 = Info#cus_push_badge{badge = Count},
            mnesia:dirty_write(cus_push_badge_tab, Info1)
    end.


get_push_user_info(Uid) ->
    case mnesia:dirty_read(cus_push_user_tab, Uid) of
        [] ->
            undefined;
        [UserInfo] ->
            UserInfo
    end.
